/**
 * 
 */
package totalFileSize;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @author mingfan
 *
 * Calculate total file size of a give path by using ForkJoinPool
 */
public class TotalFileSizeForkJoin {
	
	private static ForkJoinPool forkjoinThreadPool = new ForkJoinPool();
	
	private static class FileSizeFinder extends RecursiveTask<Long> {
		
		private final File targetPath;
		
		public FileSizeFinder(final File path) {
			targetPath = path;		
		}

		@Override
		protected Long compute() {
			long totalFileSize = 0;
			
			if (targetPath.isFile()) {
				totalFileSize = targetPath.length();
			} else {
				final File[] bunchOfFiles = targetPath.listFiles();
				if (bunchOfFiles != null) {
					final List<ForkJoinTask<Long>> tasks = new ArrayList<>();
					for (File aFile : bunchOfFiles) {
						if (aFile.isFile()) {
							totalFileSize += aFile.length();
						} else {
							tasks.add(new FileSizeFinder(aFile));
						}	
					}
					for (final ForkJoinTask<Long> oneTask : invokeAll(tasks)) {
						totalFileSize += oneTask.join();
					}					
				}
			}
			return totalFileSize;
		}
		
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final String targetPath = "/lib";
		System.out.println("Start on path: " + targetPath);
		final long start = System.nanoTime();
		final long size = forkjoinThreadPool.invoke(new FileSizeFinder(new File(targetPath)));
		final long end = System.nanoTime();
		System.out.printf("Total file size on path %s is %d.%n", targetPath, size);
		System.out.println("Time used: " + (end - start)/1.0e9);
	}

}
